#pragma once

#include"Sem.hpp"
#include"Mutex.hpp"
#include<vector>

namespace RingQueueModule
{
    using namespace SemModule;
    using namespace LockModule;

    
    template<typename T>
    class RingQueue
    {
    public:
        RingQueue(int cap)
        :_ring(cap)
        ,_cap(cap)
        ,_p_step(0)
        ,_c_step(0)
        ,_datasem(0)
        ,_spacesem(cap)
        {}

        void Equeue(const T& in)
        {
            _spacesem.P();//如果小于0会阻塞，本质计数器--
           
            //要保证生产是原子的，不然会覆盖
            {
                LockGuard lockguard(_p_lock);//用guard的构造和析构来加锁和解锁
                _ring[_p_step]=in;
                _p_step++;
                _p_step%=_cap;
            }
            _datasem.V();
        }

        void Pop(T* out)
        {
            _datasem.P();

            {
                LockGuard lockguard(_c_lock);
                *out=_ring[_c_step];
                _c_step++;
                _c_step%=_cap;
            }
            _spacesem.V();
        }
    private:
    //生产消费位置不一样，那就生产和生产 消费和消费，互斥就行，用锁 
    //一样，那就是空或者满了，那不仅要互斥，还要同步，用信号量
        std::vector<T> _ring;//环，临界资源
        int _cap;//容量
        int _p_step;//生产位置
        int _c_step;//消费位置

        Sem _datasem;//数据信号量  信号量不就是之前计数器的作用吗  本质就是个计数器
        Sem _spacesem;//空间信号量

        Mutex _p_lock;//定义时构造函数直接初始化好
        Mutex _c_lock;

    };
}